陀螺仪数据处理(BMI088)

您所在的位置:网站首页 acc 接线 陀螺仪数据处理(BMI088)

陀螺仪数据处理(BMI088)

2023-10-04 03:00| 来源: 网络整理| 查看: 265

1.BMI088惯性传感器介绍 1.1传感器原理图

BMI088电路原理图 传感器采用3.3V供电,使用SPI/IIC通讯模式(本文采用SPI通讯协议)。

1.2传感器功能介绍

传感器主要参数 ***注:***这里提到的数据读取频率 2000Hz是陀螺仪的数据最快读取频率,其加速度计的数据最快读取频率为1600Hz,加速度测量单位g为重力加速度,陀螺仪测量单位°/s为角度单位,这里注意角度制和弧度制的区别,三角函数使用的是弧度制。 陀螺仪传感器内部寄存器对照表: BMI088陀螺仪传感器寄存器对照表 加速度传感器内部寄存器对照表: BMI088加速度传感器寄存器对照表 ***注意:***BMI088作为一款成熟的惯性器件,可以读取传感器当前工作温度,但是温度传感器挂载与加速度计部分,这也就是说如果准备做温度补偿,需要在读取加速度计数据的同时读取温度数据。 数据读取模式选择:读取频率、数据范围、以及滤波带宽的选择: 加速度计部分: 加速度计配置寄存器-1 加速度计配置寄存器-2 陀螺仪部分: 陀螺仪寄存器配置-1 陀螺仪寄存器配置-2 详细说明以及官方例程请见: 链接:https://pan.baidu.com/s/1OeIyNdDWo1UlggMcK_LXlg 提取码:6789 –来自百度网盘超级会员V4的分享

2.BMI088陀螺仪数据读取 2.1传感器初始化配置

BMI088.c文件:

/*!*************************************************** * @file: BMI088.c * @brief: 用于配置BMI088陀螺仪 加速度计的各项参数并读取数据 * @author: * @date:2022/05/31 * @note: ****************************************************/ #include "BMI088.h" #include "spi.h" #define SPI1_ACC_Enable { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0 #define SPI1_ACC_Disable { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0 #define SPI1_GYRO_Enable { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);}//PA4 PB0 #define SPI1_GYRO_Disable { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0 #define CS_GYRO 0 #define CS_ACC 1 #define BOARD_IMU 0 #define FLOAT_IMU 1 /* 用于读取BMI088温度数据 */ #define BMI088_accel_read_muli_reg(reg, data, len) \ { \ BMI088_ACCEL_NS_L(); \ BMI088_read_write_byte((reg) | 0x80); \ BMI088_read_muli_reg(reg, data, len); \ BMI088_ACCEL_NS_H(); \ } /*!*************************************************** * @file: BMI088.c * @brief: 用于BMI088传感器中的软件延时 * @author: * @date:2022/05/31 * @note: ****************************************************/ static void BMI088_Delay(int times) { delay_ms(times); } /*!*************************************************** * @file: BMI088.c * @brief: 通过SPI通讯总线读取和发送传感器数据 * @author: * @date:2022/05/31 * @note: ****************************************************/ static uint8_t BMI088_SPIReadSend(uint8_t data) { uint8_t ret = 0xff; HAL_SPI_TransmitReceive(&hspi1, &data, &ret, 1, 0xffff); return ret; } /*!*************************************************** * @file: BMI088.c * @brief: 用于读取陀螺仪的数据 * @author: * @date:2022/05/31 * @note: 已经知道读取陀螺仪数据的函数,如果想使用数据,需要知道滤波函数的用法 ****************************************************/ static uint8_t BMI088_Read_GYRO(uint8_t Addr, int BOARD_OR_FLOAT) { uint8_t val; SPI1_GYRO_Enable BMI088_SPIReadSend(Addr | 0x80); val = (uint8_t)(BMI088_SPIReadSend(0x00) & 0xFF); SPI1_GYRO_Disable; return val; } /*!*************************************************** * @file: BMI088.c * @brief: 用于读取加速度计的数据 * @author: * @date:2022/05/31 * @note: 已经知道读取加速度计数据的函数,如果想使用数据,需要知道滤波函数的用法 ****************************************************/ static uint8_t BMI088_Read_ACC(uint8_t Addr, int BOARD_OR_FLOAT) { uint8_t val; SPI1_ACC_Enable BMI088_SPIReadSend(Addr | 0x80); BMI088_SPIReadSend(0x00) ; val = (uint8_t)(BMI088_SPIReadSend(0x00) & 0xFF); SPI1_ACC_Disable return val; } /*!*************************************************** * @file: BMI088.c * @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法 * @author: * @date:2022/05/31 * @note: ****************************************************/ static void BMI088_Write_Reg(uint8_t Addr, uint8_t Val, uint8_t ACC_OR_GYRO) { if (ACC_OR_GYRO == CS_ACC) { SPI1_ACC_Enable } else if (ACC_OR_GYRO == CS_GYRO) { SPI1_GYRO_Enable } BMI088_SPIReadSend(Addr & 0x7f); BMI088_SPIReadSend(Val); if (ACC_OR_GYRO == CS_ACC) { SPI1_ACC_Disable } else if (ACC_OR_GYRO == CS_GYRO) { SPI1_GYRO_Disable } } /*!*************************************************** * @file: BMI088.c * @brief: 用于配置初始化传感器中的加速度计 * @author: * @date:2022/05/31 * @note: 配置加速度计产生中断的IO口的输出方式,数据输出频率1600hz 加速度量程是 ±24g 有点大,目前的车无需这么大的量程 ****************************************************/ /** * @brief * @retval 尝试降低采样率是否能提高数据稳定性 * @date: 2021/10/17 */ int ret = 0; static uint8_t BMI088_ACC_Congfig(int BOARD_OR_FLOAT) { SPI1_ACC_Disable; BMI088_Write_Reg(0x7e, 0xb6, CS_ACC);//Soft Reset while (BMI088.acc_id != ACC_CHIP_ID) //Rising edge ,turn to spi { BMI088_Delay(100); BMI088.acc_id = BMI088_Read_ACC(0x00, BOARD_OR_FLOAT); //id:1E } BMI088_Delay(50);//> 1 ms ; ret = 0; while (ret != ACC_ON) { ret = BMI088_Read_ACC(ACC_PWR_CTRL, BOARD_OR_FLOAT); BMI088_Write_Reg(ACC_PWR_CTRL, ACC_ON, CS_ACC); BMI088_Delay(5); } **/* 可根据实际使用和加速度寄存器表修改加速度计测量范围 */** while (BMI088_Read_ACC(ACC_RANG, BOARD_OR_FLOAT) != Plus_Minus_24G) { BMI088_Write_Reg(ACC_RANG, Plus_Minus_24G, CS_ACC); //ACC Rang +- 24g;// BMI088_Delay(5); } while (BMI088_Read_ACC(0x40, BOARD_OR_FLOAT) != 0xBC) { /* 可根据实际使用和加速度寄存器表修改加速度计数据读取频率 */ BMI088_Write_Reg(0x40, 0xBC, CS_ACC); // BMI088_Delay(5); } while (BMI088_Read_ACC(0X53, BOARD_OR_FLOAT) != 0X08) { BMI088_Write_Reg(0X53, 0X08, CS_ACC); //0000 1000 INT1 OUTPUT PUSH-PULL Active low BMI088_Delay(5); } while (BMI088_Read_ACC(0X54, BOARD_OR_FLOAT) != 0X08) { BMI088_Write_Reg(0X54, 0X08, CS_ACC); //0000 1000 INT2 OUTPUT PUSH-PULL Active low BMI088_Delay(5); } while (BMI088_Read_ACC(0X58, BOARD_OR_FLOAT) != 0x44) { BMI088_Write_Reg(0X58, 0x44, CS_ACC); //0100 0100 data ready interrupt to INT1 and INT2 BMI088_Delay(5); } BMI088_Delay(20);//>1ms while (BMI088_Read_ACC(ACC_PWR_CONF, BOARD_OR_FLOAT) != ACC_ACTIVE) { BMI088_Write_Reg(ACC_PWR_CONF, ACC_ACTIVE, CS_ACC); //ACtive mode BMI088_Delay(600);//>50ms } return 0; } /*!*************************************************** * @file: BMI088.c * @brief: 用于配置初始化传感器中的陀螺仪 * @author: * @date:2022/05/31 * @note: 配置陀螺仪产生中断的IO口的输出方式,数据输出频率2000hz ****************************************************/ static uint8_t BMI088_GYRO_Congfig(int BOARD_OR_FLOAT) { SPI1_ACC_Disable; while (BMI088.gyro_id != GYRO_CHIP_ID) { BMI088.gyro_id = BMI088_Read_GYRO(0x00, BOARD_OR_FLOAT); //0x0f BMI088_Delay(5); } while (BMI088_Read_GYRO(GYRO_RANG, BOARD_OR_FLOAT) != Plus_Minus_2000) { BMI088_Write_Reg(GYRO_RANG, Plus_Minus_2000, CS_GYRO);// rang +-2000 BMI088_Delay(5); } //bit #7 is Read Only /* 可根据陀螺仪寄存器对照表陀螺仪采样率是2000hz */ BMI088_Write_Reg(GYRO_BANDWIDTH, ODR_1000_FD_116, CS_GYRO); while (BMI088_Read_GYRO(0X11, BOARD_OR_FLOAT) != 0x00) { BMI088_Write_Reg(0X11, 0x00, CS_GYRO);//normal BMI088_Delay(5); } while (BMI088_Read_GYRO(0X15, BOARD_OR_FLOAT) != 0X80) { BMI088_Write_Reg(0X15, 0X80, CS_GYRO);// //interrupt BMI088_Delay(5); } while (BMI088_Read_GYRO(0X16, BOARD_OR_FLOAT) != 0X00) { BMI088_Write_Reg(0X16, 0X00, CS_GYRO);//OUTPUT PUSH-PULL Active low BMI088_Delay(5); } while (BMI088_Read_GYRO(0X18, BOARD_OR_FLOAT) != 0X81) { BMI088_Write_Reg(0X18, 0X81, CS_GYRO);//data ready interrupt to INT1 and INT2 BMI088_Delay(5); } return 0; } /*****************************以下几个函数用于读取BMI088传感器的温度数据****************************/ /*!*************************************************** * @file: BMI088.c * @brief: 用于读取陀螺仪加速度传感器高八位数据 * @author: * @date:2022/05/31 * @note: 参考的大疆源码BMI088传感器的温度补偿控制 温度传感器应该是挂载在加速度传感器上,所以读取温度 需要使用加速度传感器 ****************************************************/ static void BMI088_ACCEL_NS_H(void) { HAL_GPIO_WritePin(CS1_ACCEL_GPIO_Port, CS1_ACCEL_Pin, GPIO_PIN_SET); } /*!*************************************************** * @file: BMI088.c * @brief: 用于读取陀螺仪加速度传感器低八位数据 * @author: * @date:2022/05/31 * @note: 参考的大疆源码BMI088传感器的温度补偿控制 温度传感器应该是挂载在加速度传感器上,所以读取温度 需要使用加速度传感器 ****************************************************/ static void BMI088_ACCEL_NS_L(void) { HAL_GPIO_WritePin(CS1_ACCEL_GPIO_Port, CS1_ACCEL_Pin, GPIO_PIN_RESET); } /*!*************************************************** * @file: BMI088.c * @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法 * @author: * @date:2022/05/31 * @note: 该函数与 BMI088_Write_Reg 函数不同,使用的时候需要注意 ****************************************************/ static uint8_t BMI088_read_write_byte(uint8_t txdata) { uint8_t rx_data; HAL_SPI_TransmitReceive(&hspi1, &txdata, &rx_data, 1, 1000); return rx_data; } /*!*************************************************** * @file: BMI088.c * @brief: 用于读取BMI088传感器中多个寄存器的数据 * @author: * @date:2022/05/31 * @note: 参考的大疆源码BMI088传感器的温度补偿控制 ****************************************************/ static void BMI088_read_muli_reg(uint8_t reg, uint8_t *buf, uint8_t len) { BMI088_read_write_byte(reg | 0x80); while (len != 0) { *buf = BMI088_read_write_byte(0x55); buf++; len--; } } /***************************************************************************************************/ /*!*************************************************** * @file: BMI088.c * @brief: 用于配置初始化传感器中的陀螺仪和加速度计 * @author: * @date:2022/05/31 * @note: ****************************************************/ uint8_t BMI088_FLOAT_ACC_GYRO_Init(void) { BMI088_ACC_Congfig(FLOAT_IMU); BMI088_GYRO_Congfig(FLOAT_IMU); return 1; } /*!*************************************************** * @file: BMI088.c * @brief: 用于读取传感器的温度 * @author: * @date: 2021/10/18 * @note: 读取出来温度进行温度补偿 ****************************************************/ void BMI088_Read_TMP(float *temperate) { int16_t bmi088_raw_temp; bmi088_raw_temp = (int16_t)((BMI088.temp_originalbuff[0] 5)); if (bmi088_raw_temp > 1023) { bmi088_raw_temp -= 2048; } *temperate = bmi088_raw_temp * BMI088_TEMP_FACTOR + BMI088_TEMP_OFFSET; } /* 按键外部中断定义变量 */ extern uint8_t exit_flag; extern uint8_t rising_falling_flag; /*!*************************************************** * @file: BMI088.c * @brief: 用于配置初始化传感器中的陀螺仪 * @author: * @date:2022/05/31 * @note: I/O外部中断回调函数,用于接收陀螺仪和加速度数据 ****************************************************/ /* 定义变量用于读取陀螺仪数据具体传输频率 */ int16_t Gyro_Cnt = 0; void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if( mtime.Init_OK!=1) return; switch (GPIO_Pin) { case GPIO_PIN_4://ACC BMI088.ACC.buff[0] = BMI088_Read_ACC(0X12, FLOAT_IMU); BMI088.ACC.buff[1] = BMI088_Read_ACC(0X13, FLOAT_IMU); BMI088.ACC.buff[2] = BMI088_Read_ACC(0X14, FLOAT_IMU); BMI088.ACC.buff[3] = BMI088_Read_ACC(0X15, FLOAT_IMU); BMI088.ACC.buff[4] = BMI088_Read_ACC(0X16, FLOAT_IMU); BMI088.ACC.buff[5] = BMI088_Read_ACC(0X17, FLOAT_IMU); **/* 用于读取传感器的温度 */ BMI088_accel_read_muli_reg(BMI088_TEMP_M, BMI088.temp_originalbuff, 2);** break; case GPIO_PIN_5://GYRO BMI088.GYRO.buff[0] = BMI088_Read_GYRO(0X02, FLOAT_IMU); BMI088.GYRO.buff[1] = BMI088_Read_GYRO(0X03, FLOAT_IMU); BMI088.GYRO.buff[2] = BMI088_Read_GYRO(0X04, FLOAT_IMU); BMI088.GYRO.buff[3] = BMI088_Read_GYRO(0X05, FLOAT_IMU); BMI088.GYRO.buff[4] = BMI088_Read_GYRO(0X06, FLOAT_IMU); BMI088.GYRO.buff[5] = BMI088_Read_GYRO(0X07, FLOAT_IMU); /* 陀螺仪的引脚触发中断一次,计数+1,用于确定陀螺仪传感器实际的传输频率 break; default: break; } }

BMI088.h文件:

/*!*************************************************** * @file: BMI088.c * @brief: 用于配置BMI088陀螺仪 加速度计的各项参数并读取数据 * @author: * @date: 2022/05/31 * @note: ****************************************************/ #ifndef __BMI088_H__ #define __BMI088_H__ #define ACC_CHIP_ID 0X1E #define ACC_PWR_CTRL 0X7D #define ACC_OFF 0X00 #define ACC_ON 0X04 #define ACC_PWR_CONF 0X7C #define ACC_ACTIVE 0X00 #define ACC_SUSPEND 0X03 /* 加速度量程范围设定 */ #define ACC_RANG 0X41 #define Plus_Minus_3G 0X00 #define Plus_Minus_6G 0X01 #define Plus_Minus_12G 0X02 #define Plus_Minus_24G 0X03 /* 加速度信号输出频率设定 */ #define BMI088_ACC_ODR_SHFITS 0x0 #define BMI088_ACC_12_5_HZ (0x5 Error_Handler(); } } /* 进一步对SPI进行配置,包括引脚映射初始化 */ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(spiHandle->Instance==SPI1) { /* SPI1 clock enable */ __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**SPI1 GPIO Configuration PB4 ------> SPI1_MISO PB3 ------> SPI1_SCK PA7 ------> SPI1_MOSI */ GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } } /* 本函数具体作用是取消SPI对以上功能的配置 */ void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) { if(spiHandle->Instance==SPI1) { /* Peripheral clock disable */ __HAL_RCC_SPI1_CLK_DISABLE(); /**SPI1 GPIO Configuration PB4 ------> SPI1_MISO PB3 ------> SPI1_SCK PA7 ------> SPI1_MOSI */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_4|GPIO_PIN_3); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7); } }

在根据以上代码配置完SPI通讯之后,只需要调用如下函数,即可完成对BMI088传感器的所有初始化:

BMI088_FLOAT_ACC_GYRO_Init();

陀螺仪数据读取.c文件

/*!*************************************************** * @brief: 用于配置对陀螺仪加速度计进行单位换算 * @note: ****************************************************/ #include "BMI088.h" //陀螺仪零偏矫正 mpu BMI088; /** * @brief 读取陀螺仪的数据 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 2000hz */ void BMI088_Read_Gyro_Data(void) { BMI088.gyro.origin [xx] = BMI088.GYRO.data[xx]; BMI088.gyro.origin [yy] = BMI088.GYRO.data[yy]; BMI088.gyro.origin [zz] = BMI088.GYRO.data[zz]; } /** * @brief 读取加速度计的数据 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 1600hz */ void BMI088_Read_Acc_Data(void) { BMI088.acc.origin [xx] = BMI088.ACC.data[xx]; BMI088.acc.origin [yy] = BMI088.ACC.data[yy]; BMI088.acc.origin [zz] = BMI088.ACC.data[zz]; } /** * @brief 读取温度 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 1600hz */ void BMI088_Read_Tmp_Data(void) { BMI088_Read_TMP(&BMI088.Temperature); } /*!*************************************************** * @file: MYGYROData.c * @brief:读取加速度,并转换为 m/(s^2) * @note: ****************************************************/ void IMU_Read(void) { mpu *mympu=&BMI088; BMI088_Read_Gyro_Data(); /* 读取陀螺仪数据 */ BMI088_Read_Acc_Data(); /* 读取加速度数据 */ mympu->gyro.dps[xx] = mympu->gyro.origin[xx] * MPU_GYRO_TO_DPS; mympu->gyro.dps[yy] = mympu->gyro.origin[yy] * MPU_GYRO_TO_DPS; mympu->gyro.dps[zz] = mympu->gyro.origin[zz] * MPU_GYRO_TO_DPS; mympu->acc.m_s_2 [xx] = mympu->acc.origin[xx] * MPU_ACCE_M_S_2; mympu->acc.m_s_2 [yy] = mympu->acc.origin[yy] * MPU_ACCE_M_S_2; mympu->acc.m_s_2 [zz] = mympu->acc.origin[zz] * MPU_ACCE_M_S_2; }

陀螺仪数据读取.h文件

/*!*************************************************** * @file: MYGYROData.c * @brief: 用于配置对陀螺仪加速度计进行数据单位换算 * @note: ****************************************************/ #define BMI088 BMI088 #define xx 0 #define yy 1 #define zz 2 #define G_Z 0 /*陀螺仪加速度计去零漂方式选择*/ #define MPU_ACC_CALOFFSET_AUTO #define MPU_GROY_CALOFFSET_AUTO /*---------------------------------------------*/ #define XAISN (3) //3个坐标 #define ITEMS 6 #define MPU9250_FILTER_NUM 4 #define MPU_CORRECTION_FLASH 0x0800F000 //存储校正数据的FLASH地址,SIZE=6*3*4字节 #define GG 9.8 // 重力加速? /* 现在量程设定为±6g */ #define MPU_ACCE_M_S_2 (24.0 * GG / 32768.0) //单位换算,将LSB化为m/(s^2),GG前面的"X"需根据量程修改 #define MPU_GYRO_TO_DPS (2000 / 32768.0) //单位换算,将LSB化为 gegree/s #define MPU_MAGN_TO_GS (4800 / 16384.0 / 100.0) //单位换算,将LSB化为Gs #define MPU_MAGN_TO_UT (4800 / 16384.0) //单位换算,将GS化为UT #define MPU_TEMP_K (0.002995177763f) //degC/LSB typedef struct _accdata { short origin[XAISN]; //原始值 float offset[XAISN]; //零偏值 float offset_max[XAISN]; //零偏值最大值 float offset_min[XAISN]; //零偏值最小值 float calibration[XAISN]; //校准值 float filter[XAISN]; //滑动平均滤波值 float m_s_2[XAISN]; //米每二次方秒 } accdata; typedef struct _gyrodata { short origin[XAISN]; //原始值 float offset_max[XAISN]; //零偏值最大值 float offset_min[XAISN]; //零偏值最小值 float offset[XAISN]; //零偏值 float calibration[XAISN]; //校准值 float filter[XAISN]; //滑动平均滤波值 float dps[XAISN]; //度每秒 float radps[XAISN]; //弧度每秒 /* 2022-01-11 加入滑动滤波 */ float last_filter[XAISN]; } gyrodata; struct _mpu { accdata acc; gyrodata gyro; float Temperature; uint8_t acc_id, gyro_id; union { int16_t data[3]; uint8_t buff[6]; } ACC, GYRO; uint8_t temp_originalbuff[2]; uint8_t gyro_times; uint8_t acc_times; enum { ReadingACC, ReadingGYRO, IDLE, } state; float pitch; float roll; float yaw; float lastyaw; /* 记录陀螺仪累计旋转多少度 */ float yawsum; /* 陀螺仪动态数据矫正 */ uint8_t DynamicOffsetEnable; // 是否进行动态校准标志位 int32_t DynamicTmp[3]; // 动态数据累加 uint32_t DynamicTimes; // 校准时间计数 uint16_t OffsetCnt; // 校准周期 uint16_t OffsetErrorRange; // 校准误差范围 float gyro_z; int16_t yaw_turns; }; typedef struct _mpu mpu; extern mpu BMI088; /** * @brief 读取陀螺仪的数据 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 2000hz */ void BMI088_Read_Gyro_Data(void); /** * @brief 读取加速度计的数据 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 1600hz */ void BMI088_Read_Acc_Data(void); /** * @brief 读取温度 * @retval 将读取出来的数据赋值给原始数 * @note data数据长度是3 原始数据长度是3 采集出来的数据就是原始数据 * @attention 从这开始实际的频率编程 1600hz */ void BMI088_Read_Tmp_Data(void); /*!*************************************************** * @file: MYGYROData.c * @brief:读取加速度,并转换为 m/(s^2) * @note: ****************************************************/ void IMU_Read(void);

以上代码如何使用将在第三章进行展现。

3.BMI088陀螺仪数据处理:

通过碰撞测试发现,180s时间内BMI088会产生15度的0点漂移,碰撞时的振动以及底盘加减速带来的冲击确实会使得陀螺仪0点发生漂移,但是加减速带来的冲击对陀螺仪的数据影响最大,也就是说在车运动过程中突然换因为惯性打滑导致车体的振动对传感器数据的影响更大。 决定使用MATLAB调用FFT函数,观测信号频谱图,根据信号频谱确定基波频率和主要谐波频率,然后使用二阶低通滤波算法,确定采样频率和截止频率,将滤波效果最大化,提高代码的运行效率。 4096点FFT的MATLAB代码如下:

clear all clc %测试代码 %t = 0:0.005:1; %时间间隔为0.005 采样频率为200hz %x= sin(2*pi*30*t)+sin(2*pi*500*t); % N = 4096; %使用1024点快速傅里叶变换 filename = '33.xlsx'; %读取数据 x = xlsread(filename); f=x; subplot(121); plot(f); %画出原始信号的波形图 ylabel('幅值'); xlabel('时间'); title('原始信号'); y=abs(fft(f,N)); %对原始信号进行离散傅里叶变换,参加DFT的采样点个数为N ff=200*(0:(N/2-1))/N; %计算变换后不同点所对应的频率值 N点只需打印一半即可,另一半是对称的 subplot(122); plot(ff,y(1:(N/2))); %画出信号的频谱图 ylabel('功率谱密度'); xlabel('频率'); title('信号功率谱图')

得出部分数据频谱图如下所示(左侧为原始数据,右侧为数据频谱图): 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 这里就不公开数据集了,因为采用不同的测试平台,采集到的数据波形可能是不同的,通过观察以上频谱图可以确定基波频率在0-5Hz,10Hz附近的信号频率即可认为是高频谐波,于是采用二阶低通滤波的方式,采样频率设定为50hz,截止频率设置为10hz,传感器中断读取频率为1000hz,滤波算法执行频率为500hz,采用积分的方法,以0.002s为单位时间进行积分,最终得到当前效果,在运行过程中,启动停止,突然换向以及撞击所造成的陀螺仪数据抖动,基本上可以说完全消除,不旋转只撞击的情况下,240s内yaw轴数据可以稳定在1.5°以内。 二阶低通滤波代码如下:

/** * @brief 二阶低通滤波函数 * @param[in] 对应传感器 * @param[in] 样本数据频率 * @param[in] 截止频率 * @retval none * @note */ void LPF2pSetCutoffFreq(int index, float sample_freq, float cutoff_freq) { LPF *lpf; lpf = &lpf4[index]; float fr = 0; float ohm = 0; float c = 0; fr = sample_freq / cutoff_freq; ohm = tanf(M_PI_F / fr); c = 1.0f + 2.0f * cosf(M_PI_F / 4.0f) * ohm + ohm * ohm; /* 直接给出截止频率减少运算步骤 */ lpf->_cutoff_freq1 = cutoff_freq; if (lpf->_cutoff_freq1 > 0.0f) { lpf->_b01 = ohm * ohm / c; lpf->_b11 = 2.0f * lpf->_b01; lpf->_b21 = lpf->_b01; lpf->_a11 = 2.0f * (ohm * ohm - 1.0f) / c; lpf->_a21 = (1.0f - 2.0f * cosf(M_PI_F / 4.0f) * ohm + ohm * ohm) / c; } } /** * @brief 二阶低通滤波函数 * @param[in] 对应传感器 * @param[in] 样本数据 * @retval 二阶低通滤波函数 */ float LPF2pApply(int index, float sample) { LPF *lpf; lpf = &lpf4[index]; float delay_element_0 = 0, output = 0; if (lpf->_cutoff_freq1 delay_element_0 = sample - lpf->_delay_element_11 * lpf->_a11 - lpf->_delay_element_21 * lpf->_a21; // do the filtering if (isnan(delay_element_0) || isinf(delay_element_0)) { // don't allow bad values to propogate via the filter delay_element_0 = sample; } output = delay_element_0 * lpf->_b01 + lpf->_delay_element_11 * lpf->_b11 + lpf->_delay_element_21 * lpf->_b21; lpf->_delay_element_21 = lpf->_delay_element_11; lpf->_delay_element_11 = delay_element_0; // return the value. Should be no need to check limits return output; } }

在采用二阶低通滤波之后,发现如果因为其它原因带来的尖峰数据会对陀螺仪Yaw轴积分结果造成影响,这里先对原始数据进行平滑滤波处理,平滑滤波之后再进行二次低通滤波,最终对数据积分得到Yaw轴角度: 平滑滤波处理:

/*!*************************************************** * @file: IMU.c * @brief: 对陀螺仪的数据进行处理 * @date: 2021/12/25 ****************************************************/ #define BMI088_FILTER_NUM 10 #define BMI088_ITEMS 3 void IMU_Filter(void) { u8 i; /* 平滑滤波数组参数定义 */ int32_t FILT_TMP[BMI088_ITEMS] = {0}; static int16_t FILT_BUF[BMI088_ITEMS][BMI088_FILTER_NUM] = {0}; BMI088_Read_Gyro_Data(); /* 读取陀螺仪数据 */ for(i=BMI088_FILTER_NUM - 1;i>=1;i--) { FILT_BUF[zz][i] = FILT_BUF[zz][i-1]; } FILT_BUF[zz][0] = BMI088.gyro.origin[zz]; for(i=0; i /* 计算零漂 */ if( g_GetZero_Offset BMI088.lastyaw += BMI088.gyro.dps[zz] * d_t; /* 积分结算Yaw轴角度 */ BMI088.gyro_z = BMI088.gyro.dps[zz]; /* 传递当前角速度数值 */ } /* 将角度限制在±180° */ if(BMI088.lastyaw > 180.0f) { BMI088.lastyaw = BMI088.lastyaw - 360; BMI088.yaw_turns ++; } else if(BMI088.lastyaw uint16_t tempPWM; /* 粗略计算5s,系统开始运行 */ static uint32_t time = 0; //pid calculate. PID计算 /* 温度读取 */ BMI088_Read_Tmp_Data(); PID_calc(&imu_temp_pid,BMI088.Temperature,40.0f); if (imu_temp_pid.out /* 当读取的温度数据第一次大于40之后陀螺仪开始正常工作 */ mtime.Temp_OK = 1; } } 5.BMI088陀螺仪总结

总的来说改款陀螺仪的稳定性还是非常高的,比传统的MPU6050拥有更高的精度和更强的稳定性,但是存在的唯一的缺陷就是,该陀螺仪的陀螺仪数据读取频率和加速度计的读取频率,只有在400hz及以下时达成一致,这显然是非常难受的一件事,在高频段,陀螺仪采样频率是2000、1000、400hz,加速度计的采样率是1600、800、400hz,如果使用加速度计进行数据融合采用互补滤波的算法校准结算欧拉角,显然这种不同频的数据读取影响是非常大的,本人也是在尝试了多个融合算法之后发现,两个传感器数据不同步对结算的影响真的不小,所以根据实际应用场景,选择了对Yaw轴角速度进行积分结算出Yaw轴角度进行使用。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3